/*
* ========== Copyright Header Begin ==========================================
* 
* OpenSPARC T1 Processor File: options.c
* Copyright (c) 2006 Sun Microsystems, Inc.  All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES.
* 
* The above named program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License version 2 as published by the Free Software Foundation.
* 
* The above named program is distributed in the hope that it will be 
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
* General Public License for more details.
* 
* You should have received a copy of the GNU General Public
* License along with this work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
* 
* ========== Copyright Header End ============================================
*/
/*
 * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

#pragma ident	"@(#)options.c	1.24	06/06/12 SMI"

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>

#include "basics.h"
#include "allocate.h"
#include "fatal.h"
#include "list.h"
#include "options.h"
#include "strutil.h"
#include "fileutil.h"

options_t options;


#ifndef NDEBUG
uint64_t debug_bits = 0ULL;
uint64_t debug_bits_xor = -1ULL;
#endif

#define	DBGPA(s)	do { s } while (0)



#define	DEFAULT_PORT		65400
#define	DEFAULT_RETRY_MAX	64

void (*mbox_trap)(simcpu_t *sp) = NULL;
void (*fpga_intr)(int bit) = NULL;

void help()
{
	printf("Usage: sim [-p | --port debugger-port]" \
		"\n\t[-P | --portmax port]" \
		"\n\t[-a | --autos]" \
		"\n\t[-M | --no-magic-traps]" \
		"\n\t[-z | --analyzer]" \
		"\n\t[-b | --buffer log-buffering-size]" \
		"\n\t[-L | --lib-path path_to_plugins]" \
		"\n\t[-debug debug_bits]" \
		"\n\t[-debugxor debug_bits]" \
		"\n\t[-t | --threads threads]" \
		"\n\t[-h | --help]" \
		"\n\t[-v | --verbose]" \
		"\n\tconfig_file\n");

}

void usage()
{
	printf("sim: illegal option\n");
	help();
}

	/*
	 * pre-configuration of selectable options
	 * before looking at command line
	 */

static void init_options()
{
	options.cpp_optionsp = (char *)0;
	options.config_filep = (char *)0;
	options.accept_port = DEFAULT_PORT;
	options.port_retry_max = DEFAULT_RETRY_MAX;
	options.specific_port = false;
	options.flag_auto_start = false;
	options.magic_traps = true;
	options.analyzer = false;
	options.buffersz = -1;	/* auto-determine */
	options.bufferp = NULL;	/* incase we need to reallocate sometime */
	options.threads = sysconf(_SC_NPROCESSORS_ONLN);
#if VERBOSE
	options.verbose = true;
#else
	options.verbose = false;
#endif

	LIST_INIT(options.libpath, char);
}

void banner_print(void)
{
	char *banner_string =
"##							\n"\
"##        ######   #####     ##    ######   ##    ##	\n"\
"##        ##      ##   ##    ##   ##    ##  ###   ##	\n"\
"##        #####   ##         ##   ##    ##  ## #  ##	\n"\
"##        ##      ##  ###    ##   ##    ##  ##  # ##	\n"\
"##        ##      ##   ##    ##   ##    ##  ##   ###	\n"\
"#######   ######   #####     ##    ######   ##    ##	";


	printf("%s\n", banner_string);
	printf("Copyright 2006 Sun Microsystems, Inc.  All rights reserved.\n");
	version_print();

}

void version_print()
{
	extern char *datestamp;
	static char *versionp = "0.1";

	printf("Legion version %s compiled on %s\n",
		versionp, datestamp);

	PRINTF(("Legion build options:\n"));

#if DEBUG_BUILD
	PRINTF(("\n\t**DEBUG BUILD**\n"));
#endif

#if NON_DEBUG_BUILD
	PRINTF(("\t**NON DEBUG BUILD**\n"));
#endif

#if HOST_OS_SOLARIS
	PRINTF(("\tHost OS: Solaris\n"));
#endif

#if HOST_CPU_SPARC_V9
	PRINTF(("\tHost CPU: sparcV9\n"));
#endif

#if DEBUG
	PRINTF(("\tDEBUG enabled\n"));
#endif

#if ENABLE_MAGIC_TRAPS
	PRINTF(("\tENABLE_MAGIC_TRAPS enabled\n"));
#endif

#if PERFORMANCE_CHECK
	PRINTF(("\tPERFORMANCE_CHECK enabled\n"));
#endif

#if ERROR_INJECTION
	PRINTF(("\tERROR_INJECTION enabled\n"));
#endif

#if CONSOLE_RESET
	PRINTF(("\tCONSOLE_RESET enabled\n"));
#endif

#if OLDPIC
	PRINTF(("\tOLDPIC enabled\n"));
#endif

#if DEBUG_TL_RAISE
	PRINTF(("\tDEBUG_TL_RAISE enabled\n"));
#endif

#if DEBUG_GL_RAISE
	PRINTF(("\tDEBUG_GL_RAISE enabled\n"));
#endif

#if DEBUG_HOOK
	PRINTF(("\tDEBUG_HOOK enabled\n"));
#endif

#if ERROR_TRAP_GEN
	PRINTF(("\tERROR_TRAP_GEN enabled\n"));
#endif

#if HYPERPRIVILEGED_USE_WARN
	PRINTF(("\tHYPERPRIVILEGED_USE_WARN enabled\n"));
#endif

#if NIAGARA_RUST_JBI_STORES
	PRINTF(("\tNIAGARA_RUST_JBI_STORES enabled\n"));
#endif

#if INTERNAL_BUILD
	PRINTF(("\tINTERNAL_BUILD enabled\n"));
#else
	PRINTF(("\tEXTERNAL_BUILD enabled\n"));
#endif

	PRINTF(("\n"));

}

#define	DEF_PLUGIN_DIR	"./plugins"


bool_t process_opts(int argc, char ** argv)
{
	int i;
	char *p;
	char *strp;

	init_options();

	for (i = 1; i < argc && argv[i][0] == '-'; i++) {
		char *p;

		p = &(argv[i][1]);

		if (streq(p, "h") || streq(p, "-help")) {
			version_print();
			help();
			exit(0);
		} else
		if (streq(p, "p") || streq(p, "-port")) {
			int num;
			if (++i >= argc) {
				usage();
				exit(1);
			}
			num = atol(argv[i]);
			if (num == 0) {
			    usage();
			    fatal("Illegal value for port number %s", argv[i]);
			}
			options.accept_port = num;
			options.specific_port = true;
		} else
		if (streq(p, "P") || streq(p, "-portmax")) {
			int num;
			if (++i >= argc) {
				usage();
				exit(1);
			}
			num = atol(argv[i]);
			if (num == 0) {
			    usage();
			    fatal("Illegal value for portmax %s", argv[i]);
			}
			options.port_retry_max = num;
		} else
		if (streq(p, "a") || streq(p, "-autos")) {
			options.flag_auto_start = true;
		} else
		if (streq(p, "M") || streq(p, "-no-magic-traps")) {
			options.magic_traps = false;
		} else
		if (streq(p, "z") || streq(p, "-analyzer")) {
			options.analyzer = true;
		} else
		if (streq(p, "b") || streq(p, "-buffer")) {
			int num;
			if (++i >= argc) {
				usage();
				exit(1);
			}
			if (options.buffersz != -1) {
				usage();
				fatal("-buffer option already set at %d"
				    " dont specify option twice!\n",
				    options.buffersz);
			}
			num = atol(argv[i]);
			options.buffersz = num;
		} else
		if (streq(p, "t") || streq(p, "-threads")) {
			int num;
			if (++i >= argc) {
				usage();
				exit(1);
			}
			num = atol(argv[i]);
			options.threads = num;
			if (options.threads > sysconf(_SC_NPROCESSORS_ONLN)) {
				fprintf(stderr, "\nUsing more threads (%d)"
				    " than available CPUs (%d) lowers"
				    " overall performance!\n\n",
				    options.threads,
				    sysconf(_SC_NPROCESSORS_ONLN));
			}
		} else
		if (streq(p, "L") || streq(p, "-lib-path")) {
			char *namep;

			if (++i >= argc) {
				usage();
				exit(1);
			}
			namep = argv[i];

				/*
				 * check to see if path dir really exists here
				 */
			if (!is_a_dir(namep)) {
				usage();
				fatal("%s is not a valid library directory",
				    namep);
			}

			strp = Xstrdup(namep);
			LIST_ADD_PTR(options.libpath, char, strp);
		} else
		if (streq(p, "v") || streq(p, "-verbose")) {
			options.verbose = true;
		} else
#ifndef NDEBUG
		if (streq(p, "debug")) {
			if (++i >= argc) {
				usage();
				exit(1);
			}
			debug_bits = strtoll(argv[i], NULL, 0);
		} else
		if (streq(p, "debugxor")) {
			if (++i >= argc) {
				usage();
				exit(1);
			}
			debug_bits_xor = strtoll(argv[i], NULL, 0);
		} else
#endif
		{
			usage();
			fatal("Illegal option %s", p);
		}
	}


		/*
		 * Additional cleanup for library search paths
		 */
	p = getenv("SIM_LIB_PATH");
	if (NULL != p) {
		if (is_a_dir(p)) {
			strp = Xstrdup(p);
			LIST_ADD_PTR(options.libpath, char, strp);
		}
	}

		/*
		 *
		 */
	if (is_a_dir(DEF_PLUGIN_DIR)) {
		strp = Xstrdup(DEF_PLUGIN_DIR);
		LIST_ADD_PTR(options.libpath, char, strp);
	}



DBGPA(
	int o;
	PRINTF(("Library search paths:"));
	for (o = 0; o < options.libpath.count; o++) {
		char *p;
		p = LIST_ENTRY(options.libpath, o);
		PRINTF((" %s", p));
	}
	PRINTF(("\n"));
);

		/*
		 * assume any non option provided is the name
		 * of a config file
		 */

	if (i == argc-1) {
		options.config_filep = Xstrdup(argv[i]);
	} else {
		/* no config filed specified? */
		usage();
		exit(1);
	}


		/*
		 * If any stdout/stderr buffering requested might as well
		 * specify it here and get it out of the way ...
		 */

	if (options.buffersz != -1) {
		if (options.buffersz <= 0) {
			(void) setvbuf(stdout, NULL, _IOLBF, 0);
			(void) setvbuf(stderr, NULL, _IOLBF, 0);
		} else {
			options.bufferp = Xmalloc(options.buffersz);
			(void) setvbuf(stdout, options.bufferp,
			    _IOFBF, options.buffersz);
		}
	}

	return (false);
}



	/*
	 * Essentially this function attempts to consolidate
	 * default values with options chosen on the command line
	 * and check the sanity of the final result.
	 * A side effect is to print the welcome banner for the program
	 */

void consolidate(void)
{
	PRINTF(("Ready to accept debugger accesses on port %d\n",
		options.accept_port));
	printf("\n");
}
